#include "amever.h"
#include "map.h"

void *map_init(unsigned int id, const char *mypath, const char *name) {
	printf("In map init.");
	FILE *fh;
	struct world_map *me = (struct world_map *)malloc(sizeof(struct world_map));
	if ((fh = fopen(mypath, "r")) == 0) {
		amelog("Couldn't open map file for reading and quitting, I guess.\n");
		server_shut("Couldn't open map.\n");
	}

	me->map_id = id;
	me->height = MAP_MAX_HEIGHT;
	me->width = MAP_MAX_WIDTH;
	me->mobs = chain_setInit(0, 0, MAP_MAX_MOBS);
	me->npcs = chain_setInit(0, 0, 255);
	amelog("My name now is %s\n", name);
	strcpy(me->name, name);

	int x = 0;
	int y = 0;

	struct world_cell *cell;
	char tmp[128];
	while (fgets(s.buffy, sizeof(s.buffy), fh) && y < MAP_MAX_HEIGHT) {
		if (s.buffy[0] == 'P' || s.buffy[0] == 'N') {
			if (y == 0)
				me->width = strlen(s.buffy) - 1;
			for (x=0; x<me->width; x++) {
				cell = (struct world_cell *)malloc(sizeof(struct world_cell));
				memset(cell, 0, sizeof(struct world_cell));
				if (s.buffy[x] == 'P' || s.buffy[x] == 'p')
				{
					cell->passable = 1;
				}
				else
				{
					cell->passable = 0;
				}
				cell->X = x;
				cell->Y = y;
				cell->objects = 0;
				cell->wmap = me;
				me->cells[y][x] = cell;
				if (x < 3 && y < 3)
				{
					amelog("%d:%d is %d coz in map we have '%c'\n", me->cells[y][x]->X, me->cells[y][x]->Y, me->cells[y][x]->passable, s.buffy[x]);
				}
			}
			memset(s.buffy, 0, 255);
			y++;
		} 
		else if (sscanf(s.buffy, "name:%[a-zA-Z0-9]", tmp) == 1) {
			amelog("Setting name to %s\n", tmp);
			strcpy(me->name, tmp);
		} 
		else if (sscanf(s.buffy, "lua(%[a-zA-Z0-9/\\.])", tmp) == 1) {
			if (!s.L)
				amelog("Lua is not there yet (%s trying to lua_dofile(%s)).\n", mypath, tmp);
			else {
				amelog("Calling %s from %s\n", tmp, mypath);
				amelog("Setting global.\n");
				lua_getglobal(s.L, "map_register");
				amelog("Pushing lightdata.\n");
				lua_pushlightuserdata(s.L, me);
				amelog("Pushing numba.\n");
				lua_pushnumber(s.L, id);
				amelog("Pushin string.\n");
				lua_pushstring(s.L, me->name);
				amelog("Calling...\n");
				lua_call(s.L, 3, 1);
				amelog("Setting global.\n");
				lua_setglobal(s.L, "map");
				lua_dofile(s.L, tmp);
			}
		}
	}
	me->height = y;
	amelog("Map %s (%dx%d) successfuly loaded.\n", me->name, me->width, me->height);
	amelog("Map->mobs 0x%p inited.\n", me->mobs);
	fclose(fh);
	return me;
}

void map_shut(struct world_map *me) {
	int y, x;
	amelog("Shutting a %s map with %d mobs and %d npcs.\n", me->name, me->mobs->len, me->npcs->len);
	chain_setShut(me->chars);
	struct chain_node *n;
	for (n=me->mobs->first;n && n->val;n=n->next)
		mob_shut((struct world_mob *)n->val);
	chain_setShutFreePointers(me->npcs);
	for (y=0;y<me->height;y++) {
		for (x=0;x<me->width;x++) {
			if (me->cells[y][x]->objects)
			chain_setShut(me->cells[y][x]->objects);
			free(me->cells[y][x]);
		}
	}
	free(me);// Not really correct but oh well...
}

int map_foreach(int type, struct world_cell *cell, int radius,
		struct chain_set *result) {
	if (!cell)
		return 0;
	int y, x;
	int x0 = cell->X - radius >= 0 ? cell->X - radius : 0;
	int y0 = cell->Y - radius >= 0 ? cell->Y - radius : 0;
	int x1 = cell->X + radius > cell->wmap->width ? cell->wmap->width : cell->X
			+ radius;
	int y1 = cell->Y + radius > cell->wmap->height ? cell->wmap->height
			: cell->Y + radius;

	struct world_cell *icell;
	struct chain_node *noderator;
	for (y=y0; y<=y1; y++) {
		for (x=x0; x<=x1; x++) {
			icell = cell->wmap->cells[y][x];
			if (icell && icell->objects && icell->objects->len > 0) {
				noderator = icell->objects->first;
				while (noderator) {
					if (type & noderator->index) {
						chain_nodeInit(result, noderator->val,
								noderator->index, 0);
					}
					// amelog("Type is %d but index is %d : %d\n", type, noderator->index, type & noderator->index);
					noderator = noderator->next;
				}
			}
		}
	}
	return result->len;
}

void map_moveObject(struct world_object *object, struct world_cell *cell) {
}

void map_startMove(struct world_object *object, unsigned short int x,
		unsigned short int y) {
	//FIXME: redundant code with packets.c
	struct chain_set *tmp = chain_setInit(0, 0, 0);
	if (map_foreach(WO_CHAR, object->cell, CHAR_RADIUS, tmp)) {
		struct chain_node *node;
		for (node=tmp->first; node; node=node->next) {
			if (CHAR(node->val)->client) {
				WFIFOPR(CHAR(node->val)->client, 8);
				WFIFOW(CHAR(node->val)->client, 0) = 21;
				WFIFOW(CHAR(node->val)->client, 2) = object->id;
				WFIFOW(CHAR(node->val)->client, 4) = x;
				WFIFOW(CHAR(node->val)->client, 6) = y;
				WFIFOSP(CHAR(node->val)->client, 8);
			}
		}
	}
	chain_setShut(tmp);
}

void *map_lookup(short int id) {
	return 0;
}

struct world_cell * map_getCell(struct world_map *me, unsigned int x,
		unsigned int y, int hastToBePassable) {
	if (x > MAP_MAX_WIDTH || y > MAP_MAX_HEIGHT || !CELL(me->cells[y][x]) || (hastToBePassable && !CELL(me->cells[y][x])->passable)) {
		return 0;
	}
	return CELL(me->cells[y][x]);
}

struct chain_node *map_addObject(struct world_cell *cell,
	struct chain_node *position, int type, void *value) {
	if (!cell) {
		amelog("No cell in insertIntoCell!\n");
		return (struct chain_node *)0;
	}

	if (position) {
		CHAIN_UNLINK(position);
	} else {
		amelog("Here.\n");
		position = malloc(sizeof(struct chain_node));
		position->val = value;
		position->index = type;
	}
	
	if (!cell->objects)
		cell->objects = chain_setInit(0, 0, 255);

	chain_nodeInit(cell->objects, 0, type, position);
	return position;
}

struct world_npc *map_addNPC(const char *name, struct world_cell *cell, int id, int looklike)
{
	struct world_npc *npc = (struct world_npc *)malloc(sizeof(struct world_npc));
	strcpy(npc->name, name);
	npc->id = id;
	npc->looklikeid = looklike;
	npc->cell = cell;
	map_addObject(cell, 0, WO_NPC, npc);
	chain_nodeInit(cell->wmap->npcs, npc, 0, 0);
	return npc;
}
